package edu.sjtu.grid.workflow.schedule;


import edu.sjtu.grid.workflow.facts.Facts;
import edu.sjtu.grid.workflow.facts.Run;



public abstract class ScheduleBase {
	
	public enum ScheduleType{
		Cheapest,
		HEFT,
		HeuristicSearch,
		HeuristicSearch_AvgCost,
		HeuristicSearch_AvgCost_Wait,
		HeuristicSearch_InitialCost,
		MDPSearch
	}
	public static String toScheduleTypeString(ScheduleType st) {
		if(st == ScheduleType.Cheapest)
			return "Cheapest";
		else if(st == ScheduleType.HEFT)
			return "HEFT";
		else if(st == ScheduleType.HeuristicSearch)
			return "HeuristicSearch";
		else if(st == ScheduleType.HeuristicSearch_AvgCost)
			return "HeuristicSearch_AvgCost";
		else if(st == ScheduleType.HeuristicSearch_AvgCost_Wait)
			return "HeuristicSearch_AvgCost_Wait";
		else if(st == ScheduleType.HeuristicSearch_InitialCost)
			return "HeuristicSearch_InitialCost";
		else if(st == ScheduleType.MDPSearch)
			return "MDPSearch";
		else
			return "unknown schedule type";
	}
	public static ScheduleType toScheduleType(String s)
	{
		for(ScheduleType st : ScheduleType.values())
			if(toScheduleTypeString(st).equals(s))
				return st;
		return null;
	}
	
	private Facts facts = null;
	private ScheduleType scheduleType = null;
	private Run run = null;
	
	private Long beginTime = null;
	private Long endTime = null;
	private boolean result = false;
	
	private int maxRunTime = 60; //second
	
	
	public String toString(String info)
	{
		StringBuilder s = new StringBuilder();
		
		s.append("----------" + this.facts.getFileName() 
				+ "[" + ScheduleBase.toScheduleTypeString(this.scheduleType)
				+ "]----------\n");
		s.append(info);
		s.append("Result:  \t" + this.result + "\n");
		s.append("Run time:\t" + (this.endTime-this.beginTime) + "\n");
		if(!this.result)
			return s.toString();
		s.append(this.run.toString() + "\n");
		return s.toString();
	}
	
	public String toString()
	{
		return this.toString("");
	}
	
	public ScheduleBase(Facts facts, ScheduleType scheduleType)
	{
		this.facts = facts;
		this.scheduleType = scheduleType;
		this.run = new Run(facts, scheduleType);
	}
	
	public boolean schedule(int maxRunTime) {
		this.maxRunTime = maxRunTime;
		return this.schedule();
	}
	public boolean schedule() {
		this.beginTime = System.currentTimeMillis();
		//this.beginTime = System.nanoTime();
		
		doSchedule();
		
		this.endTime = System.currentTimeMillis();
		//this.endTime = System.nanoTime();
		
		if(result)
			this.run.realRun();
		
		this.run.setRuntime(((double)this.endTime - this.beginTime) / 1000);
		
		return result;
	}
	
	public Facts getFacts() {
		return facts;
	}

	public Run getRun() {
		return run;
	}

	public Long getBeginTime() {
		return beginTime;
	}

	public Long getEndTime() {
		return endTime;
	}

	protected boolean reachMaxRunTime()
	{
		return (System.currentTimeMillis() - this.beginTime) / 1000 >= this.maxRunTime;
	}
	
	public boolean isResult() {
		return result;
	}
	
	public void setResult(boolean result) {
		this.result = result;
		if(result)
		{
			this.run.setSucc(true);
			this.facts.getRuns().addRun(this.run);
		}
		else
		{
			this.run.setSucc(false);
			this.facts.getRuns().addRun(this.run);
		}
	}
	
	public void setResult(boolean result, Run run) {
		this.run = run;
		setResult(true);
		this.run.realRun();
	}
	protected abstract void doSchedule();
}
